package com.itany.shop.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.itany.shop.exception.DataAccessException;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author 石小俊
 */
public class JDBCUtil {

    private static DataSource ds;
    private static ThreadLocal<Connection> local;

    static {
        local = new ThreadLocal<>();
        Properties p = new Properties();
        try {
            p.load(JDBCUtil.class.getClassLoader().getResourceAsStream("dataSouece.properties"));
            // commons-dbcp
            // ds = BasicDataSourceFactory.createDataSource(p);
            // druid
            ds = DruidDataSourceFactory.createDataSource(p);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("JDBCUtil初始化失败");
        }
    }

    /**
     * 获取连接
     * 使用数据库连接池获取一个线程单例的链接
     * @return
     */
    public static Connection getConnection() {
        // 线程池:存放单例连接的ThreadLocal
        // 数据库连接池:commons-dbcp或者druid
        // 从线程池中获取连接
        Connection conn = local.get();
        try {
            // 如果在线程池中没有获取到连接,说明尚未获取过
            if (conn == null) {
                // 从数据库连接池中获取一个连接
                conn = ds.getConnection();
                // 当获取到连接之后,为了便于下次使用的同一个连接
                // 将当前获取的连接存放到线程池中
                local.set(conn);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn;
    }

    /**
     * 释放持久层资源
     * 根据实际需求,选择需要释放的资源
     * 如果某个资源不需要释放,则传递参数为null即可
     * @param conn 连接
     * @param ps   状态集
     * @param rs   结果集
     */
    public static void close(Connection conn, PreparedStatement ps, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new DataAccessException("释放连接失败!");
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                throw new DataAccessException("释放状态集失败!");
            }
        }
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new DataAccessException("释放结果集失败!");
            }
        }
    }

    /**
     * 释放业务层资源
     * 一般在事务执行完毕之后进行释放
     * 此时需要释放连接、释放线程池中的资源
     */
    public static void close() {
        // 从线程池中获取连接
        Connection conn = local.get();
        // 如果获取到连接,则说明尚未释放
        try {
            if (conn != null) {
                // 释放连接
                conn.close();
                // 业务执行完毕之后,此时线程池中的连接已经不需要了
                // 因此,从线程池中释放资源
                local.remove();
            }
        } catch (SQLException e) {
            throw new DataAccessException("释放业务层资源失败!");
        }
        // 如果没有获取到连接,说明已经释放了,不需要在此释放
    }
}
